#ifndef _LISTMAP_HPP_
#define _LISTMAP_HPP_

#include "jhdefs.hpp"

#include "charset/string.hpp"
using namespace JHCPP::charset;

#include <list>
#include <utility>

NET_NAMESPACE_BEGIN

template <class Key, class Mapped, class Container = std::list<std::pair<Key, Mapped> >, bool CaseSensitive = false >
class TListMap
{
public:
	typedef Key                 KeyType;
	typedef Mapped              MappedType;
	typedef Mapped&             Reference;
	typedef const Mapped&       ConstReference;
	typedef Mapped*             Pointer;
	typedef const Mapped*       ConstPointer;

	typedef typename Container::value_type     ValueType;
	typedef typename Container::size_type      SizeType;
	typedef typename Container::iterator       Iterator;
	typedef typename Container::const_iterator ConstIterator;

	TListMap()
	{
	}

	TListMap(std::size_t initialReserve) : m_list(initialReserve)
	{
	}

	TListMap& operator = (const TListMap& map)
	{
		TListMap tmp(map);
		swap(tmp);
		return *this;
	}

	void swap(TListMap& map)
	{
		m_list.swap(map.m_list);
	}

	ConstIterator begin() const
	{
		return m_list.begin();
	}

	ConstIterator end() const
	{
		return m_list.end();
	}

	Iterator begin()
	{
		return m_list.begin();
	}

	Iterator end()
	{
		return m_list.end();
	}

	ConstIterator find(const KeyType& key) const
	{
		typename Container::const_iterator it = m_list.begin();
		typename Container::const_iterator end = m_list.end();
		for(; it != end; ++it)
		{
			if (isEqual(it->first, key)) return it;
		}
		return end;
	}

	Iterator find(const KeyType& key)
	{
		typename Container::iterator it = m_list.begin();
		typename Container::iterator end = m_list.end();
		for(; it != end; ++it)
		{
			if (isEqual(it->first, key)) return it;
		}
		return end;
	}

	Iterator insert(const ValueType& val)
	{
		Iterator it = find(val.first);

		if (it == m_list.end())
		{
			m_list.push_back(val);
			it = m_list.end();
			--it;
		}
		else
		{
			m_list.insert(it, 1, val);
		}

		return it;
	}

	void erase(Iterator it)
	{
		m_list.erase(it);
	}

	SizeType erase(const KeyType& key)
	{
		SizeType count = 0;
		Iterator it = find(key);
		bool removed = false;
		while (it != m_list.end())
		{
			if (isEqual(it->first, key))
			{
				++count;
				it = m_list.erase(it);
				removed = true;
			}
			else
			{
				if (removed) return count;
				++it;
			}
		}
		return count;
	}

	void clear()
	{
		m_list.clear();
	}

	std::size_t size() const
	{
		return m_list.size();
	}

	bool empty() const
	{
		return m_list.empty();
	}

	ConstReference operator [] (const KeyType& key) const
	{
		ConstIterator it = find(key);
		if (it != m_list.end())
			return it->second;
		else
			throw NotFoundException();
	}

	Reference operator [] (const KeyType& key)
	{
		Iterator it = find(key);
		if (it != m_list.end())
			return it->second;
		else
		{
			ValueType value(key, Mapped());
			Iterator it = insert(value);
			return it->second;
		}
	}

private:
	template <typename T1, typename T2>
	bool isEqual(T1 val1, T2 val2) const
	{
		return val1 == val2;
	}

	bool isEqual(const std::string& s1, const std::string& s2) const
	{
		if (!CaseSensitive)
			return icompare(s1, s2) == 0;
		else
			return s1 == s2;
	}

	bool isEqual(const std::string& s1, const char* s2) const
	{
		return isEqual(s1, std::string(s2));
	}

	bool isEqual(const char* s1, const std::string& s2) const
	{
		return isEqual(std::string(s1), s2);
	}

	bool isEqual(const char* s1, const char* s2) const
	{
		return isEqual(std::string(s1), std::string(s2));
	}

	Container m_list;
};

NET_NAMESPACE_END

#endif
